#ifndef __THREAD_H__
#define __THREAD_H__
/////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
//Thread Manager Class..experimenting with 'Self Contained' class without use of msvcrt et al..
//Current can only manage 0x4b0 /0xc = 100 threads, this can manage..
class ThreadManager {
public:
	//no need for new or delete operators...
	ULONG _status ;
	ULONG Index,_CurrentIndex;
	PVOID _ThisThreadHeap;
	HANDLE _threadHandle;
	int _dbgEnabled;
	CONTEXT _context;
    ThreadManager() {
		PVOID _ThisThreadHeap = HeapAlloc(GetProcessHeap(),0,0x4b0);
		memset(_ThisThreadHeap,(int)INVALID_HANDLE_VALUE,0x4b0);
	}
	~ThreadManager() {
		for(ULONG i = 0;i < ThreadManager::_CurrentIndex;i++)
		{
			if(getThisHeapThreadHandle(i) != INVALID_HANDLE_VALUE)
			{
				if(!::CloseHandle(getThisHeapThreadHandle(i)))
				{
					return;
				}
			}
		}
		::HeapFree(GetProcessHeap(),0,_ThisThreadHeap);
		::HeapDestroy(GetProcessHeap());
	}

	HANDLE OpenThisThread(ULONG ThreadId){
		Index = IsThisThreadManaged(ThreadId);
		if(Index)
		{
			if(getThisHeapThreadHandle(Index) == INVALID_HANDLE_VALUE)
			{
				if(!_dbgEnabled)
				{
					if(!NT_SUCCESS(::RtlAdjustPrivilege(20L,true,false,(PBOOLEAN)&_dbgEnabled)))
					{
						return INVALID_HANDLE_VALUE;
					}
				}
				_threadHandle = ::OpenThread(THREAD_ALL_ACCESS,false,ThreadId);
				if(_threadHandle != INVALID_HANDLE_VALUE)
				{
					setThisHeapThreadHandle(Index,(ULONG)_threadHandle);
					return _threadHandle;
				}
				else
				{
					return INVALID_HANDLE_VALUE;
				}
			}
			else
			{
				return getThisHeapThreadHandle(Index);
			}
		}
		else
		{
			if(!_dbgEnabled)
			{
				if(!NT_SUCCESS(::RtlAdjustPrivilege(20L,true,false,(PBOOLEAN)&_dbgEnabled)))
				{
					return INVALID_HANDLE_VALUE;
				}
			}
			_threadHandle = ::OpenThread(THREAD_ALL_ACCESS,false,ThreadId);
			if(_threadHandle != INVALID_HANDLE_VALUE)
			{
				setThisHeapThreadId(_CurrentIndex,ThreadId);
				setThisHeapThreadHandle(_CurrentIndex,(ULONG)_threadHandle);
				_CurrentIndex++;
				return _threadHandle;
			}
			else
			{

				return INVALID_HANDLE_VALUE;
			}
		}
	}

	HANDLE CreateThisThread(bool CreateSuspended,bool IsUserThread,HANDLE ThisProcess,ULONG Start,PVOID Param){
		if(IsUserThread)
		{
			if(CreateSuspended)
			{
				setThisHeapThreadHandle(_CurrentIndex,(ULONG)::CreateThread(0,0x4096,(LPTHREAD_START_ROUTINE)Start,Param,CREATE_SUSPENDED,(ULONG*)getThisHeapThreadAddress(Index)));
				_CurrentIndex++;
				return getThisHeapThreadHandle(_CurrentIndex - 1);
			}
			else
			{
				setThisHeapThreadHandle(_CurrentIndex,(ULONG)::CreateThread(0,0x4096,(LPTHREAD_START_ROUTINE)Start,Param,0,(ULONG*)getThisHeapThreadAddress(Index)));
				_CurrentIndex++;
				return getThisHeapThreadHandle(_CurrentIndex - 1);
			}
		}
		else
		{
			if(CreateSuspended)
			{
				if(NT_SUCCESS(::RtlCreateUserThread(ThisProcess,0,TRUE,0,0,0,(PUSER_THREAD_START_ROUTINE)Start,Param,(PHANDLE)getThisHeapHandleAddress(_CurrentIndex),0)))
				{
					_CurrentIndex++;
					return getThisHeapThreadHandle(_CurrentIndex - 1);
				}
				return INVALID_HANDLE_VALUE;
			}
			else
			{
				if(NT_SUCCESS(::RtlCreateUserThread(ThisProcess,0,FALSE,0,0,0,(PUSER_THREAD_START_ROUTINE)Start,Param,(PHANDLE)getThisHeapHandleAddress(_CurrentIndex),0)))
				{
					_CurrentIndex++;
					return getThisHeapThreadHandle(_CurrentIndex - 1);
				}
				return INVALID_HANDLE_VALUE;
			}
		}
	}

    bool SuspendThisThread(){
		if(::SuspendThread(getThisHeapThreadHandle(_CurrentIndex)) == -1)
		{
			return false;
		}
		return true;
	}
	bool ResumeThisThread(){
		if(::ResumeThread(getThisHeapThreadHandle(_CurrentIndex)) == -1)
		{
			return false;
		}
		return true;
	}
	bool ResumeThisThreadById(ULONG ThreadId){
		Index = IsThisThreadManaged(ThreadId);
		if(Index)
		{
			if(::ResumeThread(getThisHeapThreadHandle(Index)) == - 1)
			{
				return false;
			}
			return true;
		}
		else
		{
			_threadHandle = OpenThisThread(ThreadId);
			if(_threadHandle != INVALID_HANDLE_VALUE)
			{
				if(::ResumeThread(_threadHandle) == -1)
				{
					return false;
				}
				return true;
			}
			return false;
		}
	}
	bool SuspendThisThreadById(ULONG ThreadId){
		Index = IsThisThreadManaged(ThreadId);
		if(Index)
		{
			if(::SuspendThread(getThisHeapThreadHandle(Index)) == - 1)
			{
				return false;
			}
			return true;
		}
		else
		{
			_threadHandle = OpenThisThread(ThreadId);
			if(_threadHandle != INVALID_HANDLE_VALUE)
			{
				if(::SuspendThread(_threadHandle) == -1)
				{
					return false;
				}
				return true;
			}
			return false;
		}
	}
	bool getContext(ULONG ThreadId){
		Index = IsThisThreadManaged(ThreadId);
		if(Index)
		{
			if(getThisHeapThreadHandle(Index) != INVALID_HANDLE_VALUE)
			{
				if(::GetThreadContext(getThisHeapThreadHandle(Index),&_context) != TRUE)
				{
					return false;
				}
				return   true;
			}
			else
			{
				_threadHandle = OpenThisThread(ThreadId);
				if(_threadHandle != INVALID_HANDLE_VALUE)
				{
					if(::GetThreadContext(_threadHandle, &_context) != TRUE)
					{
						return false;
					}
					return true;
				}
				return false;
			}
		}
		else
		{
			_threadHandle = OpenThisThread(ThreadId);
			if(_threadHandle != INVALID_HANDLE_VALUE)
			{
				if(::GetThreadContext(_threadHandle, &_context) != TRUE)
				{
					return false;
				}
				return true;
			}
			return false;
		}
	}
	bool setContext(ULONG ThreadId,CONTEXT *_ccontext){
		Index = IsThisThreadManaged(ThreadId);
		if(Index)
		{
			if(getThisHeapThreadHandle(Index) != INVALID_HANDLE_VALUE)
			{
				if(::SetThreadContext(getThisHeapThreadHandle(Index),(CONTEXT*)&_ccontext) != TRUE)
				{
					return false;
				}
				return true;
			}
			else
			{
				_threadHandle = OpenThisThread(ThreadId);
				if(::SetThreadContext(_threadHandle,(CONTEXT*)&_ccontext) != TRUE)
				{
					return false;
				}
				return true;
			}
		}
		else
		{
			_threadHandle = OpenThisThread(ThreadId);
			if(::SetThreadContext(_threadHandle,(CONTEXT*)&_ccontext) != TRUE)
			{
				return false;
			}
			return true;
		}
	}	
	ULONG getThisHeapThreadId(ULONG Index){
		return (*(ULONG*)((ULONG)_ThisThreadHeap + (Index * 0xc)+0x4));
	}
	ULONG IsThisThreadManaged(ULONG ThreadId){
		Index = 0;
		do
		{
			if(getThisHeapThreadId(Index) == ThreadId)
			{
				return Index;
			}
			Index++;
		}while(Index <= _CurrentIndex);
		return Index > 0 ?  0:0;
	}		

	HANDLE getThisHeapThreadHandle(ULONG Index){
		return ((HANDLE)*(ULONG*)((ULONG)_ThisThreadHeap + (Index *0xc)+0x8));
	}

	void setThisHeapThreadId(ULONG Index,ULONG ThreadId) {
		 *(ULONG*)((ULONG)_ThisThreadHeap + (Index * 0xc)+0x4) = ThreadId;
	}
	void setThisHeapThreadHandle(ULONG Index,ULONG ThreadHandle) {
		 *(ULONG*)((ULONG)_ThisThreadHeap + (Index * 0xc)+0x8)   = ThreadHandle;
	}
	ULONG getThisHeapThreadAddress(ULONG Index){
		return ((ULONG)_ThisThreadHeap + (Index * 0xc)+0x4);
	}
	ULONG getThisHeapHandleAddress(ULONG Index){
		return ((ULONG)_ThisThreadHeap + (Index * 0xc)+0x8);
	}

};
///////////////////////////////////////////////////////////////////////////////
#endif // __THREAD_H__
